package activity

import (
	"context"
	"strings"

	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"
	"mall/service/backend/common/utils/pointy"
	"mall/service/promotion/model"
	"mall/service/promotion/rpc/internal/svc"
	"mall/service/promotion/rpc/internal/utils/errorhandler"
	"mall/service/promotion/rpc/types/promotion"

	"github.com/zeromicro/go-zero/core/logx"
)

type BackendGetActivityRelationshipByIdLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBackendGetActivityRelationshipByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackendGetActivityRelationshipByIdLogic {
	return &BackendGetActivityRelationshipByIdLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BackendGetActivityRelationshipByIdLogic) BackendGetActivityRelationshipById(
	in *promotion.ActivityRelationListReq,
) (*promotion.ActivityRelationshipInfo, error) {
	if in.ActivityId == 0 {
		return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
	}

	if in.WithProducts != nil && *in.WithProducts > 0 {
		return l.getActivityProductListById(in)
	}

	if in.WithBrands != nil && *in.WithBrands > 0 {
		return l.getActivityProductBrandListById(in)
	}

	if in.WithCategorys != nil && *in.WithCategorys > 0 {
		return l.getActivityProductCategoryListById(in)
	}

	if in.WithCoupons != nil && *in.WithCoupons > 0 {
		return l.getActivityCouponListById(in)
	}

	return &promotion.ActivityRelationshipInfo{}, nil
}

func (l *BackendGetActivityRelationshipByIdLogic) getActivityProductListById(
	in *promotion.ActivityRelationListReq,
) (*promotion.ActivityRelationshipInfo, error) {
	var orderBys []string
	if len(in.OrderBy) > 0 {
		for _, orderBy := range in.OrderBy {
			var order string = " ASC"
			if orderBy.Order == "1" {
				order = " DESC"
			}
			if orderBy.Field == "id" {
				orderBys = append(orderBys, model.PromotionActivityProductRelationshipColumns.SkuID + order)
			}
		}
	}

	var stati string
	if len(in.FilterBy) > 0 {
		for _, filterBy := range in.FilterBy {
			if filterBy.Field == "status" {
				stati = filterBy.In
			}
		}
	}

	var page uint64
	var pageSize uint64
	var restricted bool
	filterMap := make(map[string]map[string][]any)
	filterMap[model.PromotionActivityProductRelationshipColumns.ActivityID] = map[string][]any{
		"equalTo": []any{in.ActivityId},
	}
	if in.Ids != nil {
		if vals := modelx.UniqueInterfaces(*in.Ids, 64); len(vals) > 0 {
			filterMap[model.PromotionActivityProductRelationshipColumns.SkuID] = map[string][]any{
				"in": vals,
			}
			restricted = true
		}
	}
	if !restricted {
		page = in.Page
		pageSize = in.PageSize
	}

	statusIn := modelx.UniqueInterfaces(stati, 32)
	statusMap := make(map[string][]any)
	if len(statusIn) > 0 {
		statusMap["in"] = statusIn
	}
	if in.Status != nil && *in.Status > 0 {
		statusMap["equalTo"] = []any{*in.Status - 1}
	}
	filterMap[model.PromotionActivityProductRelationshipColumns.Status] = statusMap

	if in.ProductType != nil {
		filterMap[model.PromotionActivityProductRelationshipColumns.ProductType] = map[string][]any{
			"equalTo": []any{*in.ProductType},
		}
	}

	var orderBy string
	if len(orderBys) > 0 {
		orderBy = strings.Join(orderBys, ",")
	} else {
		orderBy = model.PromotionActivityProductRelationshipColumns.RelationshipID
	}
	res, count, err := l.svcCtx.Activity.GetProductList(l.ctx, model.M{
		"page":     page,
		"pageSize": pageSize,
		"orderBy":  orderBy,
	}, 1, filterMap)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	resp := &promotion.ActivityRelationshipInfo{
		ActivityId: in.ActivityId,
		Total:      uint64(count),
	}
	for _, v := range res {
		resp.Products = append(resp.Products, &promotion.ActivityProductInfo{
			Id:           &v.RelationshipID,
			ActivityId:   &v.ActivityID,
			ActivityType: pointy.GetPointer(uint32(v.ActivityType)),
			ProductType:  pointy.GetPointer(uint32(v.ProductType)),
			ProductId:    &v.ProductID,
			SkuId:        &v.SkuID,
			Price:        pointy.GetPointer(moneyx.FormatAmount(int64(v.Price))),
			Inventory:    &v.Inventory,
			Sort:         pointy.GetPointer(uint32(v.Sort)),
			Status:       pointy.GetPointer(uint32(v.Status)),
		})
	}

	return resp, nil
}

func (l *BackendGetActivityRelationshipByIdLogic) getActivityProductBrandListById(
	in *promotion.ActivityRelationListReq,
) (*promotion.ActivityRelationshipInfo, error) {
	var orderBys []string
	if len(in.OrderBy) > 0 {
		for _, orderBy := range in.OrderBy {
			var order string = " ASC"
			if orderBy.Order == "1" {
				order = " DESC"
			}
			if orderBy.Field == "id" {
				orderBys = append(
					orderBys,
					model.PromotionActivityProductBrandRelationshipColumns.ProductBrandID + order,
				)
			}
		}
	}

	var stati string
	if len(in.FilterBy) > 0 {
		for _, filterBy := range in.FilterBy {
			if filterBy.Field == "status" {
				stati = filterBy.In
			}
		}
	}

	var page uint64
	var pageSize uint64
	var restricted bool
	filterMap := make(map[string]map[string][]any)
	filterMap[model.PromotionActivityProductBrandRelationshipColumns.ActivityID] = map[string][]any{
		"equalTo": []any{in.ActivityId},
	}
	if in.Ids != nil {
		if vals := modelx.UniqueInterfaces(*in.Ids, 64); len(vals) > 0 {
			filterMap[model.PromotionActivityProductBrandRelationshipColumns.ProductBrandID] = map[string][]any{
				"in": vals,
			}
			restricted = true
		}
	}
	if !restricted {
		page = in.Page
		pageSize = in.PageSize
	}

	statusIn := modelx.UniqueInterfaces(stati, 32)
	statusMap := make(map[string][]any)
	if len(statusIn) > 0 {
		statusMap["in"] = statusIn
	}
	if in.Status != nil && *in.Status > 0 {
		statusMap["equalTo"] = []any{*in.Status - 1}
	}
	filterMap[model.PromotionActivityProductBrandRelationshipColumns.Status] = statusMap

	var orderBy string
	if len(orderBys) > 0 {
		orderBy = strings.Join(orderBys, ",")
	} else {
		orderBy = model.PromotionActivityProductBrandRelationshipColumns.RelationshipID
	}
	res, count, err := l.svcCtx.Activity.GetProductBrandList(l.ctx, model.M{
		"page":     page,
		"pageSize": pageSize,
		"orderBy":  orderBy,
	}, 1, filterMap)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	resp := &promotion.ActivityRelationshipInfo{
		ActivityId: in.ActivityId,
		Total:      uint64(count),
	}
	for _, v := range res {
		resp.Brands = append(resp.Brands, &promotion.ActivityProductBrandInfo{
			Id:             &v.RelationshipID,
			ActivityId:     &v.ActivityID,
			ActivityType:   pointy.GetPointer(uint32(v.ActivityType)),
			ProductBrandId: &v.ProductBrandID,
			Sort:           pointy.GetPointer(uint32(v.Sort)),
			Status:         pointy.GetPointer(uint32(v.Status)),
		})
	}

	return resp, nil
}

func (l *BackendGetActivityRelationshipByIdLogic) getActivityProductCategoryListById(
	in *promotion.ActivityRelationListReq,
) (*promotion.ActivityRelationshipInfo, error) {
	var orderBys []string
	if len(in.OrderBy) > 0 {
		for _, orderBy := range in.OrderBy {
			var order string = " ASC"
			if orderBy.Order == "1" {
				order = " DESC"
			}
			if orderBy.Field == "id" {
				orderBys = append(
					orderBys,
					model.PromotionActivityProductCategoryRelationshipColumns.ProductCategoryID + order,
				)
			}
		}
	}

	var stati string
	if len(in.FilterBy) > 0 {
		for _, filterBy := range in.FilterBy {
			if filterBy.Field == "status" {
				stati = filterBy.In
			}
		}
	}

	var page uint64
	var pageSize uint64
	var restricted bool
	filterMap := make(map[string]map[string][]any)
	filterMap[model.PromotionActivityProductCategoryRelationshipColumns.ActivityID] = map[string][]any{
		"equalTo": []any{in.ActivityId},
	}
	if in.Ids != nil {
		if vals := modelx.UniqueInterfaces(*in.Ids, 64); len(vals) > 0 {
			filterMap[model.PromotionActivityProductCategoryRelationshipColumns.ProductCategoryID] = map[string][]any{
				"in": vals,
			}
			restricted = true
		}
	}
	if !restricted {
		page = in.Page
		pageSize = in.PageSize
	}

	statusIn := modelx.UniqueInterfaces(stati, 32)
	statusMap := make(map[string][]any)
	if len(statusIn) > 0 {
		statusMap["in"] = statusIn
	}
	if in.Status != nil && *in.Status > 0 {
		statusMap["equalTo"] = []any{*in.Status - 1}
	}
	filterMap[model.PromotionActivityProductCategoryRelationshipColumns.Status] = statusMap

	var orderBy string
	if len(orderBys) > 0 {
		orderBy = strings.Join(orderBys, ",")
	} else {
		orderBy = model.PromotionActivityProductCategoryRelationshipColumns.RelationshipID
	}
	res, count, err := l.svcCtx.Activity.GetProductCategoryList(l.ctx, model.M{
		"page":     page,
		"pageSize": pageSize,
		"orderBy":  orderBy,
	}, 1, filterMap)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	resp := &promotion.ActivityRelationshipInfo{
		ActivityId: in.ActivityId,
		Total:      uint64(count),
	}
	for _, v := range res {
		resp.Categories = append(resp.Categories, &promotion.ActivityProductCategoryInfo{
			Id:                &v.RelationshipID,
			ActivityId:        &v.ActivityID,
			ActivityType:      pointy.GetPointer(uint32(v.ActivityType)),
			ProductCategoryId: &v.ProductCategoryID,
			Sort:              pointy.GetPointer(uint32(v.Sort)),
			Status:            pointy.GetPointer(uint32(v.Status)),
		})
	}

	return resp, nil
}

func (l *BackendGetActivityRelationshipByIdLogic) getActivityCouponListById(
	in *promotion.ActivityRelationListReq,
) (*promotion.ActivityRelationshipInfo, error) {
	var orderBys []string
	if len(in.OrderBy) > 0 {
		for _, orderBy := range in.OrderBy {
			var order string = " ASC"
			if orderBy.Order == "1" {
				order = " DESC"
			}
			if orderBy.Field == "id" {
				orderBys = append(orderBys, model.PromotionActivityCouponRelationshipColumns.CouponID + order)
			}
		}
	}

	var stati string
	if len(in.FilterBy) > 0 {
		for _, filterBy := range in.FilterBy {
			if filterBy.Field == "status" {
				stati = filterBy.In
			}
		}
	}

	var page uint64
	var pageSize uint64
	var restricted bool
	filterMap := make(map[string]map[string][]any)
	filterMap[model.PromotionActivityCouponRelationshipColumns.ActivityID] = map[string][]any{
		"equalTo": []any{in.ActivityId},
	}
	if in.Ids != nil {
		if vals := modelx.UniqueInterfaces(*in.Ids, 64); len(vals) > 0 {
			filterMap[model.PromotionActivityCouponRelationshipColumns.CouponID] = map[string][]any{
				"in": vals,
			}
			restricted = true
		}
	}
	if !restricted {
		page = in.Page
		pageSize = in.PageSize
	}

	statusIn := modelx.UniqueInterfaces(stati, 32)
	statusMap := make(map[string][]any)
	if len(statusIn) > 0 {
		statusMap["in"] = statusIn
	}
	if in.Status != nil && *in.Status > 0 {
		statusMap["equalTo"] = []any{*in.Status - 1}
	}
	filterMap[model.PromotionActivityCouponRelationshipColumns.Status] = statusMap

	var orderBy string
	if len(orderBys) > 0 {
		orderBy = strings.Join(orderBys, ",")
	} else {
		orderBy = model.PromotionActivityCouponRelationshipColumns.RelationshipID
	}
	res, count, err := l.svcCtx.Activity.GetCouponList(l.ctx, model.M{
		"page":     page,
		"pageSize": pageSize,
		"orderBy":  orderBy,
	}, 1, filterMap)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	resp := &promotion.ActivityRelationshipInfo{
		ActivityId: in.ActivityId,
		Total:      uint64(count),
	}
	for _, v := range res {
		resp.Coupons = append(resp.Coupons, &promotion.ActivityCouponInfo{
			Id:           &v.RelationshipID,
			ActivityId:   &v.ActivityID,
			ActivityType: pointy.GetPointer(uint32(v.ActivityType)),
			CouponId:     &v.CouponID,
			PerLimit:     pointy.GetPointer(uint32(v.PerLimit)),
			Sort:         pointy.GetPointer(uint32(v.Sort)),
			Status:       pointy.GetPointer(uint32(v.Status)),
		})
	}

	return resp, nil
}
